#include "enhancement.h"
#include "iostream"
#include <vector>
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <string>
#define DISPLAY_SWITCH true
typedef unsigned short WORD;//WORD表示16位无符号数

using namespace std;
using namespace cv;
Mat raw2Mat(WORD * pRawData,int width,int height)
{
    int length = height * width;

//    ushort *data = (ushort *)malloc(width*height * sizeof(ushort));
//    fread(data, sizeof(ushort), width*height, fp);
    Mat image = Mat(1024,1024,CV_16UC1);

    memcpy( image.data, pRawData, length * sizeof(ushort));

    return image;
}

vector<Mat> buildGaussianPyramid(Mat &image,int level) {
    vector<Mat> pyramid;
    Mat copy = image.clone();
    pyramid.push_back(image.clone());
    Mat dst;

    for (int i = 0; i < level; i++) {
        pyrDown(copy, dst, Size(copy.cols / 2, copy.rows / 2));
        dst.copyTo(copy);
        pyramid.push_back(dst.clone());
    }

    return pyramid;
}

vector<Mat> buildLapacianPyramid(Mat &image,int level){
    vector<Mat> lp;
    Mat temp;
    Mat copy = image.clone();
    Mat dst;

    for (int i = 0; i < level; i++) {
        pyrDown(copy, dst, Size(copy.cols / 2, copy.rows / 2));
        pyrUp(dst, temp, copy.size());
        Mat lapaian;
        subtract(copy, temp, lapaian);
        lp.push_back(lapaian);
        copy = dst.clone();
    }

    return lp;
}

Mat blend(Mat &image, vector<Mat> &pyramid) {
    Mat a = pyramid[0];
    add(image,a,image);
    return image;
}

void display(Mat image, char * windowName)
{
    if (DISPLAY_SWITCH == true) {
        namedWindow(windowName, 1);
        imshow(windowName, image);
        waitKey(0);
    }
    else return;
}


Mat pyramidBlending(Mat &image,int level)
{
    vector<Mat> lpPyramid = buildLapacianPyramid(image, level);
    Mat result;
    add(image,lpPyramid[0],result);
    return result;
}

Mat Enhancement(Mat &image)
{
    Mat dst;
//    image = image / 65535 * 255;
//    image.convertTo(image, CV_8UC1, 1, 0);
//    bilateralFilter(image,dst,9,75,75);
//    display(dst,"denoising");
//    cout << dst.type() << endl;
//    dst.convertTo(dst, CV_32F, 1, 0);
//    dst = dst / 255 ;
//    cout << dst.type() << endl;
//    dst.convertTo(dst, CV_16UC1, 1, 0);
//    cout << dst.type() << endl;
//
//    display(dst,"denoising");
//    medianBlur(image,dst,5);
//    display(dst,"medianblur_denoising");
    GaussianBlur(image,dst,Size(5, 5),0,0);
//    display(dst,"gaussian_denoising");

    // 形态学运算
    Mat tophat,blackhat;
    Mat element = getStructuringElement(MORPH_ELLIPSE,Size(10,10));
    morphologyEx(dst,tophat,MORPH_TOPHAT,element);
    morphologyEx(dst,blackhat,MORPH_BLACKHAT,element);

//    display(tophat,"tophat");
//    display(blackhat,"blackhat");
    dst = image + tophat - blackhat;
    display(dst,"tophat-blackhat");
    // 金字塔融合
    dst = pyramidBlending(dst,6);
    display(dst,"pyramid");
    // 直方图均衡化
    Ptr<CLAHE> clahe = createCLAHE();
    clahe->setClipLimit(4);
    clahe->apply(image, dst);
    display(dst,"clahe");

    return dst;
}